import Enum from '../enum'
import config from '../config'
import manager from '../manager'
import { getClass, parseJsonObject, isObject, isFunction } from '@/utils/types'
import { rgb2array, hex2rgbArray, fromRgb2 } from '@/utils/color'

/** 仅供内部使用的一些函数 */

// 判断对象是否IS_CAD_COLOR_OBJECT
const IS_CAD_COLOR_OBJECT = function(value) {
  let ret = false
  try {
    // 访问下面3个属性，看是否报错
    const r = value.GetRed()
    const g = value.GetGreen()
    const b = value.GetBlue()
    const ret1 = r !== undefined
    const ret2 = g !== undefined
    const ret3 = b !== undefined
    ret = ret1 && ret2 && ret3
  } catch (err) {
    ret = false
    // console.log("IS_CAD_COLOR_OBJECT:", err);
  }
  return ret
}
// 判断对象是否有r、g、b属性
const IS_RGB_COLOR_OBJECT = function(value) {
  try {
    // 判断是否js object
    if (!isObject(value)) {
      return false
    } else if (
      !value.hasOwnProperty('r') &&
      !value.hasOwnProperty('g') &&
      !value.hasOwnProperty('b')
    ) {
      // r、g、b属性值均不包含!!!
      return false
    } else {
      return true
    }
  } catch (err) {
    return false
  }

  // try {
  //   const ret1 = value.r !== undefined
  //   const ret2 = value.g !== undefined
  //   const ret3 = value.b !== undefined
  //   ret = ret1 && ret2 && ret3
  // } catch (err) {
  //   ret = false
  //   // console.log("IS_RGB_COLOR_OBJECT:", err);
  // }
  // return ret
}

// 判断是否IMxDrawPoint类型
const IS_CAD_POINT_OBJECT = function(value) {
  let isCadPoint = false
  try {
    value.DistanceTo(value)
    value.IsEqualTo(value, 0.001)
    value.SumVector(value)
    isCadPoint = true
  } catch (err) {
    isCadPoint = false
  }
  return isCadPoint
}

// 判断对象是否有x、y属性
const IS_XYZ_POINT_OBJECT = function(value) {
  try {
    // 判断是否js object
    if (!isObject(value)) {
      return false
    } else if (
      !value.hasOwnProperty('x') &&
      !value.hasOwnProperty('y') &&
      !value.hasOwnProperty('z')
    ) {
      // x、y、z属性值均不包含!!!
      return false
    } else {
      return true
    }
  } catch (err) {
    return false
  }

  // // 判断是否包含x、y、z属性
  // let ret = false
  // try {
  //   const ret1 = value.x !== undefined
  //   const ret2 = value.y !== undefined
  //   const ret3 = value.z !== undefined
  //   ret = ret1 && ret2 && ret3
  // } catch (err) {
  //   ret = false
  //   // console.log("IS_XYZ_POINT_OBJECT:", err);
  // }
  // return ret
}

const IS_JSON_STRING = function(value) {
  if (getClass(value) !== 'String') return false
  let ret = true
  try {
    JSON.parse(value)
  } catch (err) {
    ret = false
  }
  return ret
}

// 获取值,如果value为非法值,则返回指定的默认值
const GetValue = function(value, defaultValue) {
  if (value === null || value === undefined) {
    return defaultValue
  } else {
    return value
  }
}

// 获取obj对象下的key属性
const GetPropertyObject = function(obj, key) {
  try {
    const _obj = obj[key]
    return _obj === null || _obj === undefined ? null : _obj
  } catch (err) {
    console.log('[异常]GetPropertyObject:', err, obj.ObjectName)
    return null
  }
}

const COPY_DATA_OBJECT = function(sourceObj, targetObj) {
  if (sourceObj === null || targetObj === null) return
  const keys = Object.keys(sourceObj)
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    // if (key === 'mxOcx' || key === 'vngCore') continue

    const obj = sourceObj[key]
    if (obj === null) continue

    // console.log('copy字段:', key)
    const cls = getClass(obj)
    if (cls === 'Object') {
      if (IS_XYZ_POINT_OBJECT(obj)) {
        typeof obj.x === 'number' && (targetObj[key].x = obj.x)
        typeof obj.y === 'number' && (targetObj[key].y = obj.y)
        typeof obj.z === 'number' && (targetObj[key].z = obj.z)
      } else if (IS_CAD_POINT_OBJECT(obj)) {
        targetObj[key].x = obj.x
        targetObj[key].y = obj.y
        targetObj[key].z = obj.z
      } else if (IS_CAD_COLOR_OBJECT(obj)) {
        targetObj[key].SetRGB(obj.GetRed(), obj.GetGreen(), obj.GetBlue())
      } else if (IS_RGB_COLOR_OBJECT(obj)) {
        typeof obj.r === 'number' && (targetObj[key].r = obj.r)
        typeof obj.g === 'number' && (targetObj[key].g = obj.g)
        typeof obj.b === 'number' && (targetObj[key].b = obj.b)
      } else {
        try {
          // MxDraw的object
          obj.ObjectName
          obj.ObjectID
          obj.Dxf0
        } catch (err) {
          // 只复制普通的json对象,ocx控件对象不复制!!!
          targetObj[key] = {}
          console.log('********小心递归***********', key)
          COPY_DATA_OBJECT(obj, targetObj[key])
        }
      }
    } else if (cls === 'Array') {
      // 清空数组
      targetObj[key].length = 0
      // 复制数组
      for (let j = 0; j < obj.length; j++) {
        targetObj[key].push(obj[j])
      }
    } else if (cls === 'String' || cls === 'Number' || cls === 'Boolean') {
      targetObj[key] = obj
    } else {
      //  if (cls === 'Function')
      // 暂不考虑复制函数!!!
      continue
    }
  }
}
/*
功能：给数据对象赋值
说明：赋值的形式多种多样,尽可能灵活
参数说明：fieldType  -- 字段类型
         obj         -- 数据对象
         key         -- 字段名称
        value        -- 字段值(外部传入)
重点1：数据对象obj是系统内部设计和使用的变量，普通用户无需知道它的细节
     为了保证内部使用的一致性，避免混乱，对数据对象格式规定如下：
     (1) 当fieldType = Enum.Field.POINT
          obj = { x:0, y:0 }  一个json对象,包含x和y属性,可通过 . 或 [] 运算符访问
     (2) 当fieldType = Enum.Field.COLOR
          obj = {r:0,g:0,b:0}  一个json对象,包含r、g、b属性,可通过 . 或 [] 运算符访问
          或者
          obj = mxOcx.NewComObject('IMxDrawMcCmColor')
          obj.SetRGB(r, g, b)
     (3) 当fieldType = Enum.Field.BOOLEAN
          obj = true or  false  一个布尔类型的值
     (4) 当fieldType = Enum.Field.FLOAT
          obj = 0.0  一个浮点数
     (5) 当fieldType = Enum.Field.INT
          obj = 0  一个整数
     (6) 当fieldType = Enum.Field.STRING
          obj = "test"  一个字符串
重点2：js是一门非常灵活的动态语言，变量是没有类型的,所以参数的输入形式丰富多样
      参数value也是如此，为此对value的格式规定如下：
     (1) 当fieldType = Enum.Field.POINT
          a、value = { x:0, y:0 }      一个json对象,包含x和y属性,可通过 . 或 [] 运算符访问
          b、value = mxOcx.NewPoint()  一个MxDrawPoint对象,包含x和y属性,可通过 . 运算符访问
          c、value = "{x:0,y:0}"       一个json字符串,解析成功为json对象,可通过 . 或 [] 运算符访问x和y属性
     (2) 当fieldType = Enum.Field.COLOR
          a、value = '#ffffff'  一个16进制的颜色字符串
          b、value = "(r,g,b)"  使用括号和逗号的颜色字符串
          c、value = {r:0,g:0,b:0}  一个json对象,包含r、g、b属性，可通过 . 或 [] 运算符访问
          d、value = mxOcx.NewComObject('IMxDrawMcCmColor')  一个MxDrawMcCmColor对象,通过SetRGB和GetRed、GetGreen、GetBlue等方法访问和修改颜色
     (3) 当fieldType = Enum.Field.BOOLEAN
          a、value = true or  false  一个布尔类型的值
          b、value = 1 or 0          一个数字(非0为true)
          c、value = 'true' or 'false' 一个true和false字符串
     (4) 当fieldType = Enum.Field.FLOAT
          value = 0.0  一个数字
     (5) 当fieldType = Enum.Field.INT
          obj = 0  一个数字
     (6) 当fieldType = Enum.Field.STRING
          obj = "test"  一个字符串
*/

function ToFloat(val) {
  let value = 0
  try {
    value = parseFloat(val)
    if (isNaN(value)) {
      value = 0
    }
  } catch (err) {
    value = 0
  }
  return value
}

function BUILD_ENTITY_EVENT_NAME(sType, event) {
  return 'Entity/' + sType + '/' + event
}
function BUID_COMMAND_EVENT_NAME(event) {
  return 'Editor/' + event
}

function GET_OCX() {
  // console.log(manager)
  return {
    diagram: manager.CurDiagram(),
    core: manager.CurCore()
  }
}

function DEFAULT_TYPE_VALUE(sType) {
  if (sType === Enum.Field.STRING) {
    return ''
  } else if (sType === Enum.Field.INT) {
    return 0
  } else if (sType === Enum.Field.FLOAT) {
    return 0.0
  } else if (sType === Enum.Field.BOOLEAN) {
    return false
  } else if (sType === Enum.Field.POINT) {
    return { x: 0, y: 0, z: 0 }
  } else if (sType === Enum.Field.VECTOR) {
    return { x: 1, y: 0, z: 0 }
  } else if (sType === Enum.Field.COLOR) {
    return config.misc.defaultColor
  } else {
    return null
  }
}

function IS_EQUAL(obj1, obj2) {
  // 类型不一致,认为不相等
  const type = getClass(obj1)
  if (type !== getClass(obj2)) return false
  const precision = 0.00001
  if (obj1 === null || obj1 === undefined) return true
  try {
    if (type === 'String' || type === 'Boolean') {
      return obj1 === obj2
    } else if (type === 'Number') {
      // TODO 精度写死了,应实现为全局配置!
      return Math.abs(obj1 - obj2) < precision
    } else if (type === 'Object') {
      if (IS_XYZ_POINT_OBJECT(obj1) && IS_XYZ_POINT_OBJECT(obj2)) {
        return (
          Math.abs(obj1.x - obj2.x) < precision &&
          Math.abs(obj1.y - obj2.y) < precision &&
          Math.abs(obj1.z - obj2.z) < precision
        )
      } else if (IS_CAD_POINT_OBJECT(obj1) && IS_CAD_POINT_OBJECT(obj2)) {
        return (
          Math.abs(obj1.x - obj2.x) < precision &&
          Math.abs(obj1.y - obj2.y) < precision &&
          Math.abs(obj1.z - obj2.z) < precision
        )
      } else if (IS_CAD_COLOR_OBJECT(obj1) && IS_CAD_COLOR_OBJECT(obj2)) {
        return (
          obj1.ColorIndex === obj2.ColorIndex &&
          obj1.ColorMethod === obj2.ColorMethod &&
          obj1.EntityColor === obj2.EntityColor
        )
      } else if (IS_RGB_COLOR_OBJECT(obj1) && IS_RGB_COLOR_OBJECT(obj2)) {
        return obj1.r === obj2.r && obj1.g === obj2.g && obj1.b === obj2.b
      } else {
        return false
      }
    } else {
      return false
    }
  } catch (err) {
    return false
  }
}

function GET_DATA(datas, key) {
  let args = null
  if (datas.hasOwnProperty(key)) {
    args = datas[key]
  }
  // else {
  //   // 尝试按大写读取key的数据
  //   // 因为ocx的扩展词典会自动将key变成大写!!!
  //   const uKey = key.toUpperCase()
  //   if (datas.hasOwnProperty(uKey)) {
  //     args = datas[uKey]
  //   }
  // }
  return args
}

function BUILD_ITEM(item, datas, skipNonExistent) {
  const { key } = item
  // 提取数据
  const args = GET_DATA(datas, key)
  // 跳过不存在的字段
  if (skipNonExistent && (args === null || args === undefined)) {
    return null
  }
  // 构造item数据
  const _item = { ...item }
  if (args === undefined || args === null) {
    if (item.hasOwnProperty('args') && item['args'].hasOwnProperty('default')) {
      _item.data = item['args']['default']
    } else {
      _item.data = DEFAULT_TYPE_VALUE(item.type)
    }
  } else {
    _item.data = args
  }
  if (_item.data === undefined || _item.data === null) {
    _item.data = ''
  }
  return _item
}

// 提取属性数据
// props -- 字段信息 {key, title, type}
// factory -- 数据工厂函数映射
// datas -- 图元的所有数据
// upperCase -- props中的字段名是否大写
// skipNonExistent -- 跳过不存在的字段
function BUILD_PROPERTIES(props, factory, datas, core, skipNonExistent) {
  if (!props || !datas) return []
  const propItems = []
  // const that = this
  props.forEach(item => {
    const { key } = item
    let dataItem = null
    if (factory && factory.hasOwnProperty(key)) {
      const func = factory[key]
      if (func && isFunction(func)) {
        try {
          dataItem = func(item, datas, core)
        } catch (err) {
          console.log('[BUILD_PROPERTIES]', err)
          dataItem = BUILD_ITEM(item, datas, skipNonExistent)
        }
      } else {
        dataItem = BUILD_ITEM(item, datas, skipNonExistent)
      }
    } else {
      dataItem = BUILD_ITEM(item, datas, skipNonExistent)
    }
    if (dataItem !== null) {
      propItems.push(dataItem)
    }
  })
  return propItems
}

// 动态加载图元模块
function DYNAMIC_LOAD(_module) {
  if (_module === null) return { props: null, factory: null }
  let props = null
  if (_module.hasOwnProperty('props')) {
    props = _module.props
  }
  if (props === null) return { props: null, factory: null }
  let factory = null
  if (_module.hasOwnProperty('factory')) {
    factory = _module.factory
  }
  return { props, factory }
}

function DynamicLoadDatas(type) {
  try {
    const _module = require('@/vng/property/datas/entity/' + type + '.js')
      .default
    return DYNAMIC_LOAD(_module)
  } catch (err) {
    return { props: null, factory: null }
  }
}

// 初始化扩展词典的属性数据
function INIT_EXT_DICT_DATA(type) {
  const { props } = DynamicLoadDatas(type)
  if (props && props.length > 0) {
    const data = {}
    props.forEach(item => {
      const { key } = item
      let value = ''
      if (
        item.hasOwnProperty('args') &&
        item['args'].hasOwnProperty('default')
      ) {
        value = item['args']['default']
      } else {
        value = DEFAULT_TYPE_VALUE(item.type)
      }
      data[key] = value
    })
    return data
  } else {
    return null
  }
}

export {
  IS_JSON_STRING,
  IS_CAD_COLOR_OBJECT,
  IS_RGB_COLOR_OBJECT,
  IS_CAD_POINT_OBJECT,
  IS_XYZ_POINT_OBJECT,
  BUILD_ENTITY_EVENT_NAME,
  BUID_COMMAND_EVENT_NAME,
  GET_OCX,
  DEFAULT_TYPE_VALUE,
  IS_EQUAL,
  BUILD_ITEM,
  BUILD_PROPERTIES,
  DYNAMIC_LOAD,
  INIT_EXT_DICT_DATA
}
